﻿using Dapper;
using DapperExtensions;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Nova.Data.DbFactory;

namespace Nova.Data
{
    public class BaseRepository<T> : IDisposable where T : class
    {
        private Database database = null;
        public BaseRepository(DatabaseType databaseType = DatabaseType.SqlServer)
        {
            database = CreateConnection(DbContext.ConnectionString, databaseType);
        }

        public Database GetConnection()
        {
            return database;
        }
        public void Dispose()
        {
            if (database != null)
            {
                database.Dispose();
            }
        }

        public IDbTransaction TranStart()
        {
            if (database.Connection.State == ConnectionState.Closed)
                database.Connection.Open();
            return database.Connection.BeginTransaction();
        }

        public void TranRollBack(IDbTransaction tran)
        {
            tran.Rollback();
            if (database.Connection.State == ConnectionState.Open)
                tran.Connection.Close();
        }

        public void TranCommit(IDbTransaction tran)
        {
            tran.Commit();
            if (database.Connection.State == ConnectionState.Open)
                tran.Connection.Close();
        }
        public string Insert(T obj, IDbTransaction tran = null, int? commandTimeOut = null)
        {
            var result = database.Insert(obj, tran, commandTimeOut);
            return result.ToString();
        }
        public bool Insert(IEnumerable<T> list, IDbTransaction tran = null, int? commandTimeOut = null)
        {
            database.Insert(list, tran, commandTimeOut);
            return true;
        }

        public bool Update(T obj, IDbTransaction tran = null, int? commandTimeOut = null)
        {
            bool result = database.Update(obj, tran, commandTimeOut, true);
            return result;
        }

        public bool Delete(T obj, IDbTransaction tran = null, int? commandTimeOut = null)
        {
            bool result = database.Delete(obj, tran, commandTimeOut);
            return result;
        }

        public bool Delete(object predicate, IDbTransaction tran = null, int? commandTimeOut = null)
        {
            bool result = database.Delete<T>(predicate, tran, commandTimeOut);
            return result;
        }

        public T GetById(string id, IDbTransaction tran = null, int? commandTimeOut = null)
        {
            T entity = null;
            entity = database.Get<T>(id, tran, commandTimeOut);
            return entity;
        }

        public T GetByField(object predicate, IList<ISort> sort = null, IDbTransaction tran = null, int? commandTimeOut = null)
        {
            T entity = null;
            entity = database.GetList<T>(predicate, sort, tran, commandTimeOut, true).FirstOrDefault();
            return entity;
        }

        public List<T> GetList(object predicate = null, IList<ISort> sort = null, IDbTransaction tran = null, int? commandTimeOut = null)
        {
            return database.GetList<T>(predicate, sort, tran, commandTimeOut, true).ToList();
        }

        public List<T> GetPage(object predicate, IList<ISort> sort, int page, int pagesize, IDbTransaction tran = null, int? commandTimeout = null, bool buffered = true)
        {
            return database.GetPage<T>(predicate, sort, page, pagesize, tran, commandTimeout, buffered).ToList();
        }

        public int Execute(string sql, object param = null, IDbTransaction tran = null, int? commandTimeOut = null, CommandType? commandType = default(CommandType?))
        {
            return database.Connection.Execute(sql, param, tran, commandTimeOut, commandType);
        }

        public object ExecuteScalar(string sql, object param = null, IDbTransaction tran = null, int? commandTimeOut = null, CommandType? commandType = default(CommandType?))
        {
            return database.Connection.ExecuteScalar(sql, param, tran, commandTimeOut, commandType);
        }

        public int Count(object predicate = null, IDbTransaction tran = null, int? commandTimeOut = null)
        {
            int count = database.Count<T>(predicate, tran, commandTimeOut);
            return count;
        }

        public T GetByCondition(string sql, object param = null, IDbTransaction tran = null, int? commandTimeOut = null, CommandType? commandType = default(CommandType?))
        {
            T entity = null;
            entity = database.Connection.Query<T>(sql, param, tran, true, commandTimeOut, commandType).FirstOrDefault();
            return entity;
        }

        public TReturn GetByCondition<TReturn>(string sql, object param = null, IDbTransaction tran = null, int? commandTimeOut = null, CommandType? commandType = default(CommandType?)) where TReturn : class
        {
            TReturn entity = null;
            entity = database.Connection.Query<TReturn>(sql, param, tran, true, commandTimeOut, commandType).FirstOrDefault();
            return entity;
        }

        public List<T> GetByConditionList(string sql, object param = null, IDbTransaction tran = null, int? commandTimeOut = null, CommandType? commandType = default(CommandType?))
        {
            return database.Connection.Query<T>(sql, param, tran, true, commandTimeOut, commandType).ToList();
        }

        public List<TReturn> GetByConditionList<TReturn>(string sql, object param = null, IDbTransaction tran = null, int? commandTimeOut = null, CommandType? commandType = default(CommandType?)) where TReturn : class
        {
            return database.Connection.Query<TReturn>(sql, param, tran, true, commandTimeOut, commandType).ToList();
        }

        public List<TReturn> GetByStoredProcedureList<TReturn>(string sql, object param = null) where TReturn : class
        {
            return database.Connection.Query<TReturn>(sql, param, commandType: CommandType.StoredProcedure).ToList();
        }
    }
}
